import React, { Component } from 'react';
import moment from 'moment';
import _ from 'lodash';
import PropTypes from 'prop-types';
import { Badge, Tooltip, Icon, Collapse, Tabs, Popover, message, Spin } from 'antd';
import cn from 'classnames';
import { getSurvivalPorts } from '@api/task';
import { IP_ALIVE_LIST_MAP, LEVEL_TYPES, LEVEL_TEXT, LEVEL_COLOR } from '@util/constants';
import OneDayDetailInfo from '@components/oneday-detail-info';
import Tag from '@components/tag';
import './index.less';

const { Panel } = Collapse;
const { TabPane } = Tabs;
const {
  LOCATION_FIELDS_MAPPING,
  TAG_FIELDS_MAPPING,
  BASE_HEADER,
  LOCATION_FIELDS,
  PORT_INFO,
  PORT_EXPAND_INFO
} = IP_ALIVE_LIST_MAP;

const MaxBadge = 9223372036854775807;

class IpAliveCard extends Component {
  constructor(props) {
    super(props);
    const defaultExpand = _.get(props, 'defaultExpand', false);
    this.state = {
      expand: defaultExpand,
      sourcePortInfo: [],
      loading: false
    };
  }

  renderCollapseItemHeader = portItem => {
    let url;
    const linkService = portItem.header.find(service => `${service.value}`.match(/^http(s)?/));
    if (linkService) {
      const service = `${linkService.value}`.match(/^http(s)?/)[0];
      url = service + '://' + this.props.detail.ip + ':' + portItem.header[0].value;
    }
    return (
      <div className="port-info-item">
        <Tooltip title="探测时间">
          <span className="port-date">{portItem.date}</span>
        </Tooltip>
        <div className="port-detail">
          {portItem.header.map((item, i) => (
            <Tooltip title={PORT_INFO[item.key] || item.key} key={'item_' + i}>
              <label>
                {item.value || item.value === 0 ? <span key={item.key}>{item.value}</span> : null}
                {url && !i && (
                  <span onClick={() => window.open(url, '_blank')} className={'linkIcon'}>
                    <label>{'>'}</label>
                  </span>
                )}
              </label>
            </Tooltip>
          ))}
        </div>
      </div>
    );
  };

  renderVulCollapseItemHeader = vulDetail => {
    const name = _.get(vulDetail, 'name', '-');
    const level = _.get(vulDetail, 'level', '-');
    return (
      <div className="port-info-item">
        <Tooltip title="漏洞名称">
          <span className="port-date">{name}</span>
        </Tooltip>
        <div className="vul-detail">
          <Tag color={LEVEL_COLOR[level]} value={LEVEL_TEXT[level] || '未知'} />
        </div>
      </div>
    );
  };

  makeLocationInfo = detail => {
    if (!detail) {
      return [];
    }

    const renderLocation = LOCATION_FIELDS.map(item => {
      let location = {};
      const path = BASE_HEADER.includes(item) ? item : `${item}.cn`;
      location.title = LOCATION_FIELDS_MAPPING[item];
      location.value = _.get(detail, path, '');
      return location;
    }).filter(item => Boolean(item.value));
    return renderLocation;
  };

  makeTagInfo = detail => {
    const tagInfo = [];
    for (let key in TAG_FIELDS_MAPPING) {
      const value = _.get(detail, key);
      if (value === true) {
        tagInfo.push({ value: TAG_FIELDS_MAPPING[key], title: TAG_FIELDS_MAPPING[key] });
      } else if (value && !Array.isArray(value)) {
        tagInfo.push({ value: value, title: TAG_FIELDS_MAPPING[key] });
      } else if (value && Array.isArray(value) && value.length > 0) {
        const strValue = value.join(' ');
        tagInfo.push({ value: strValue, title: TAG_FIELDS_MAPPING[key] });
      }
    }
    // 添加引擎操作系统
    // wmap
    let wmap = _.get(detail, 'ports', []).find(r => _.get(r, 'wmap.wmap_extra.wmap_system_name'));
    if (wmap) {
      tagInfo.push({ value: _.get(wmap, 'wmap.wmap_extra.wmap_system_name'), title: 'os' });
      return tagInfo;
    }
    // xmap
    let xmap = _.get(detail, 'ports', []).find(r => _.get(r, 'xmap.os'));
    if (xmap) {
      tagInfo.push({ value: _.get(xmap, 'xmap.os'), title: 'os' });
      return tagInfo;
    }
    // nmap
    if (_.get(detail, 'os.product')) {
      tagInfo.push({ value: _.get(detail, 'os.product'), title: 'os' });
      return tagInfo;
    }

    // 其他情况
    if (_.get(detail, 'os')) {
      tagInfo.push({ value: _.get(detail, 'os'), title: 'os' });
      return tagInfo;
    }

    return tagInfo;
  };

  dealWmapWebRender = item => {
    let wmapWebValue = '';
    const webTitle = _.get(item, 'wmap.title', '');
    const webKeywords = _.get(item, 'wmap.keywords', '');
    const webDomain = _.get(item, 'wmap.domains', []);
    const webHeader = _.get(item, 'wmap.header', '');
    const webSource = _.get(item, 'wmap.body', '');
    if (webTitle) {
      wmapWebValue += `网站标题: ${webTitle}\n`;
    }

    if (webKeywords) {
      wmapWebValue += `网站关键词: ${webKeywords}\n`;
    }

    if (webDomain.length > 0) {
      wmapWebValue += `网站域名信息: ${webDomain.join(' ')}\n`;
    }

    if (webHeader) {
      wmapWebValue += `网站header头信息: ${webHeader}\n`;
    }

    if (webSource) {
      wmapWebValue += `网站源码:\n ${webSource}\n`;
    }
    return wmapWebValue;
  };

  makePortInfo = source => {
    if (!source.length) {
      return [];
    }
    const renderPortsInfo = source.map(item => {
      let portInfoItem = {};
      portInfoItem.header = Object.keys(PORT_INFO).map(portKey => {
        let headerItem = {};
        headerItem.key = portKey;
        headerItem.value =
          portKey === 'ssl' && Boolean(_.get(item, 'xmap.ssl', ''))
            ? 'ssl'
            : _.get(item, portKey, '');
        return headerItem;
      });
      // 有英文名先使用英文名
      if (portInfoItem.header.find(key => key.key === 'productInfo.name.en').value) {
        portInfoItem.header = portInfoItem.header.filter(key => key.key !== 'productInfo.name.cn');
      }

      portInfoItem.date = moment(item.created).format('YYYY-MM-DD HH:mm:ss');
      portInfoItem.expandInfo = PORT_EXPAND_INFO.map(key => {
        let expandItem = {};
        expandItem.key = key;
        // 单独处理web信息的展示
        if (key === 'web') {
          expandItem.value = this.dealWmapWebRender(item);
        } else {
          expandItem.value = _.get(item, `xmap.${key}`, '');
        }
        return expandItem;
      }).filter(item => Boolean(item.value));
      return portInfoItem;
    });
    return renderPortsInfo;
  };

  renderVulLevelColorBlocks = vuls => {
    const levelMap = _.mapValues(_.groupBy(vuls, 'level'), value =>
      _.map(value, 'name')
        .filter(Boolean)
        .join(',')
    );
    const popoverContent = (
      <div style={{ maxWidth: 500, maxHeight: 300, overflow: 'auto', wordBreak: 'break-all' }}>
        {LEVEL_TYPES.map(typ => {
          return {
            level: typ,
            text: levelMap[typ] ? `${LEVEL_TEXT[typ]}: ${levelMap[typ]}` : ''
          };
        })
          .filter(i => i.text)
          .map((i, k) => (
            <div key={k} style={{ color: LEVEL_COLOR[i.level] }}>
              {i.text}
            </div>
          ))}
      </div>
    );
    const fatalCount = _.filter(vuls, { level: 'fatal' }).length;
    const highCount = _.filter(vuls, { level: 'high' }).length;
    const middleCount = _.filter(vuls, { level: 'middle' }).length;
    const lowCount = _.filter(vuls, { level: 'low' }).length;
    return (
      <Popover content={popoverContent}>
        <span className="color-bolcks">
          <i className={cn({ 'fatal-level-bg': fatalCount })}>{fatalCount ? fatalCount : null}</i>
          <i className={cn({ 'high-level-bg': highCount })}>{highCount ? highCount : null}</i>
          <i className={cn({ 'middle-level-bg': middleCount })}>
            {middleCount ? middleCount : null}
          </i>
          <i className={cn({ 'low-level-bg': lowCount })}>{lowCount ? lowCount : null}</i>
        </span>
      </Popover>
    );
  };

  changeExpand = async () => {
    const { expand } = this.state;
    const { detail } = this.props;
    const newDetail = { ...detail };
    // 打开详细信息时，如果没有ports字段就请求获取
    if (!expand) {
      if (!_.get(newDetail, 'ports')) {
        try {
          this.setState({ loading: true });
          const result = await getSurvivalPorts({ targetId: _.get(newDetail, '_id') });
          this.setState({ sourcePortInfo: _.get(result, 'data.data.ports', []) });
          this.setState({ loading: false });
        } catch {
          message.error('请求详情失败！');
          this.setState({ loading: false });
        }
      } else {
        this.setState({ sourcePortInfo: _.get(newDetail, 'ports', []) });
      }
    } else {
      this.setState({ sourcePortInfo: [] });
    }

    this.setState({ expand: !expand });
  };

  // eslint-disable-next-line
  componentDidUpdate(prevProps) {
    const { detail } = prevProps;
    if (!_.isEqual(detail, this.props.detail)) {
      this.setState({ expand: false });
    }
  }

  render() {
    const { expand, sourcePortInfo, loading } = this.state;
    const { detail, scanType = '' } = this.props;
    const newDetail = { ...detail };
    if (newDetail.created) {
      newDetail.detail.timeStamp = moment(newDetail.created).format('YYYY-MM-DD HH:mm:ss');
    }
    const ipTarget = _.get(newDetail, 'target', '');
    const realIp = _.get(newDetail, 'ip', '');
    const geoInfo = _.get(newDetail, 'detail', null);
    const portCount = _.get(newDetail, 'portCount', 0);
    // TODO 确认漏洞信息字段？
    const vulInfo = _.get(newDetail, 'vulInfo', []);

    // 组装需要渲染的地理位置Header信息
    const locationInfo = this.makeLocationInfo(geoInfo);
    // 组装需要渲染的Tag信息
    const tagInfo = this.makeTagInfo(newDetail);
    // 组装需要渲染的端口信息
    const portInfo = this.makePortInfo(sourcePortInfo);
    return (
      <div className="task-detection-ip-alive-card">
        <section className="base-info-header">
          <div className="ip-target-wrapper">
            <div className="ip-info-box">
              <span className="ip-target">{ipTarget}</span>
              <Tooltip placement="top" title="暴露端口数">
                <Badge
                  count={portCount}
                  style={{ background: '#207ed4', color: '#fff' }}
                  overflowCount={MaxBadge}
                />
              </Tooltip>
              <span className="analysis-ip">{realIp}</span>
              {scanType === 'Vul' && (
                <span className="exist-vul">存在漏洞数：{this.renderVulLevelColorBlocks([])}</span>
              )}
              {/* TODO renderVulLevelColorBlocks参数？漏洞等级颜色组件 */}
            </div>
            <div className="location-info-box">
              {locationInfo.map((location, index) => (
                <div className="location-item" key={index}>
                  <Tooltip placement="top" title={location.title}>
                    <span>{location.value}</span>
                  </Tooltip>
                </div>
              ))}
            </div>
          </div>
        </section>
        <section className="main-content">
          <div className="banner-box" onClick={() => this.changeExpand()}>
            <div>
              {tagInfo.map(tag => (
                <Tooltip placement="top" key={tag.title} title={tag.title}>
                  <span className="banner-item">{tag.value}</span>
                </Tooltip>
              ))}
            </div>
            <div style={{ color: '#558ac7', cursor: 'pointer', minWidth: '50px' }}>
              <Icon type={expand ? 'up' : 'down'} />
              &nbsp;{!expand ? '详细信息' : '收起'}
            </div>
          </div>
          <Spin spinning={loading} tip="加载中" className="c-finger-item-content is-loading">
            <div className={cn('port-box', { 'port-box-hidden': !expand })}>
              <div style={{ marginRight: 30, minWidth: 52 }}>端口信息</div>
              <div style={{ overflow: 'hidden' }} className="collapse">
                <Collapse
                  bordered={false}
                  defaultActiveKey={[]}
                  expandIcon={({ isActive }) => (
                    <Icon style={{ color: '#c6c6c6' }} type="down" rotate={isActive ? 180 : 0} />
                  )}
                >
                  {portInfo.map((portItem, index) => (
                    <Panel
                      header={this.renderCollapseItemHeader(portItem)}
                      key={index}
                      showArrow={Boolean(portItem.expandInfo.length)}
                      disabled={!portItem.expandInfo.length}
                    >
                      <Tabs defaultActiveKey={0} style={{ marginTop: '-15px' }} animated={false}>
                        {portItem.expandInfo.map(item => (
                          <TabPane tab={item.key} key={item.key} width={'100%'}>
                            <pre className="port-expand-item">{item.value}</pre>
                          </TabPane>
                        ))}
                      </Tabs>
                    </Panel>
                  ))}
                </Collapse>
              </div>
            </div>
            {scanType === 'VulDetect' && !_.isEmpty(vulInfo) && (
              <div className={cn('port-box', { 'port-box-hidden': !expand })}>
                <div style={{ marginRight: 30, minWidth: 52 }}>漏洞信息</div>
                <div style={{ overflow: 'hidden', width: '100%' }}>
                  <Collapse
                    bordered={false}
                    defaultActiveKey={[]}
                    expandIcon={({ isActive }) => (
                      <Icon style={{ color: '#c6c6c6' }} type="down" rotate={isActive ? 180 : 0} />
                    )}
                  >
                    {vulInfo.map((vul, index) => (
                      <Panel header={this.renderVulCollapseItemHeader(vul)} key={index}>
                        <div className="expand-vul-detail">
                          <OneDayDetailInfo data={vul} />
                        </div>
                      </Panel>
                    ))}
                  </Collapse>
                </div>
              </div>
            )}
          </Spin>
        </section>
        <div
          className="space"
          style={{ height: 5, width: '100%', background: '#f0f1f3', marginTop: !expand ? 15 : 0 }}
        />
      </div>
    );
  }
}

IpAliveCard.propTypes = {
  detail: PropTypes.object,
  defaultExpand: PropTypes.bool,
  scanType: PropTypes.string
};

export default IpAliveCard;
